package nancal.mp.service.jenkins.publish

import nancal.mp.db.mongo.GitServerTypeEnum
import nancal.mp.db.mongo.entity.dev.JenkinsLog
import nancal.mp.db.mongo.extend.getAppDeploySetting
import nancal.mp.db.mongo.mor
import nancal.mp.service.jenkins.JenkinsPublishJob
import nbcp.base.extend.*
import nbcp.base.utils.Base64Util
import nbcp.base.utils.ResourceUtil
import nbcp.base.utils.UrlUtil
import nbcp.myoql.db.mongo.queryById
import org.slf4j.LoggerFactory


class FunctionContent(var functionName: String = "", var content: String = "") {
    companion object {
        fun empty(name: String): FunctionContent {
            return FunctionContent(name, "")
        }
    }

    override fun toString(): String {
        if (functionName.isEmpty()) return ""

        return """
function ${functionName}(){
${
            content.AsString(":")
                .ToTab(1)
        }
}
"""
    }
}


class FileContent(var fileName: String = "", var bytes: ByteArray = byteArrayOf()) {

    constructor(fileName: String, content: String = "") : this(fileName, byteArrayOf()) {
        this.bytes = content.toByteArray();
    }

    companion object {
        private val logger = LoggerFactory.getLogger(this::class.java.declaringClass);

        fun fromResource(resourcePath: String, basePath: String): FileContent {
            var ret = FileContent();
            ret.fileName = resourcePath.Slice(basePath.length).trim('/');
            try {
                ret.bytes = ResourceUtil.readResourceContentBytes(resourcePath);
            } catch (e: Exception) {
                logger.error("无法读取 ${resourcePath} 内容")
                throw e;
            }
            return ret;
        }

        fun fromResources(resourcePath: String): List<FileContent> {
            var list = ResourceUtil.findResources(resourcePath);

            return list.map {
                return@map fromResource(it, resourcePath)
            }
                .filter { it.fileName.HasValue && it.bytes.size > 0 }
        }
    }
}


private fun getMainVarFile(log: JenkinsLog): FileContent {
    var appDeploySetting = mor.dev.appDeploySetting.getAppDeploySetting(log.buildInfo.targetEnv);


    var gitCloneUrl = "";
    if (log.gitData != null) {
        var gitData = log.gitData!!;
        var gitServer = mor.dev.gitServer.queryById(gitData.server.id).toEntity()!!

        if (gitData.accessToken.HasValue) {

            var at = "";

            if (gitServer.gitServerType == GitServerTypeEnum.Gitlab) {
                at = "x-access-token:" + gitData.accessToken
            } else {
                at = gitData.accessToken;
            }

            gitCloneUrl = log.getAccessTokenUrl(at)

        } else if (gitServer.userName.HasValue && gitServer.password.HasValue) {
            gitCloneUrl = log.getGitUserAndPasswordUrl(gitServer)
        } else {
            throw RuntimeException("找不到 ${log.gitData!!.url} 的 accessToken!");
        }
    } else if (log.sourceData?.zipFile?.url.isNullOrEmpty()) {
        throw RuntimeException("找不到源码!");
    }

    var folder = log.buildInfo.buildFolder.trim('.', '/').AsString(".")

    var userDefDocker = log.gitData!!.folders.first { it.path == log.buildInfo.buildFolder }.config.docker

    var buildImageName = "";

    if (userDefDocker.id.HasValue && userDefDocker.name.HasValue) {
        buildImageName = userDefDocker.name.replace("@harborHost@", appDeploySetting.harborServer.host)
    } else {
        buildImageName = appDeploySetting.getBuildImageFullName(log.language, log.languageVersion)
    }

    if (buildImageName.isEmpty()) {
        throw RuntimeException("先在环境设置中，设置编译镜像")
    }


    var content = """#!/bin/bash
export sudo="${appDeploySetting.sudo}"
export buildLogId="${log.id}"
export adminToken="${UrlUtil.encodeURIComponent(appDeploySetting.adminToken)}"
export productLine_code="${log.productLine.code}"
export productLine_name="${log.productLine.name}"
export language="${log.language.toString().lowercase()}"
export languageVersion="${log.languageVersion}"
export targetEnv="${log.buildInfo.targetEnv}"
export serviceName="${log.buildInfo.serviceName}"
export folder="${folder}"
export isLib="${log.buildInfo.isLib}"
export appName="${log.buildInfo.appName}"
export appLocation="${log.buildInfo.location}"
export appCnName="${log.buildInfo.appCnName}"
export clusterCode="${log.buildInfo.clusterCode}"
export gitBranch="${log.buildInfo.gitBranch}"
export profile="${log.buildInfo.profile}"
export msDeployEnvEnum="${log.buildInfo.msDeployEnvEnum}"
export imageTagPrefix="${log.buildInfo.imageTagPrefix}"
export dockerImageVersion="${log.buildVersion.dockerImageVersion}"
export buildScript="${log.currentGitFolder.buildScript.AsString("build")}"
export gitCommitId="${log.buildVersion.gitCommitId}"
export gitCommitAt="${log.buildVersion.gitCommitAt}"
export gitUrl="${log.gitData?.url.AsString()}"
export gitCloneUrl="${gitCloneUrl}"
export gitToken="${log.gitData?.accessToken.AsString()}"
export codeUrl="${log.sourceData?.zipFile?.url.AsString()}"
export env_timezone="${appDeploySetting.dockerEnvTimezone}"
export env_mpApiUrl="${appDeploySetting.mpIntegrationApiUrl}"
export env_pipelineTemplate="${appDeploySetting.pipelineTemplate}"
export env_dockerApiUrl="${appDeploySetting.dockerApiUrl}"
export env_harborHost="${appDeploySetting.harborServer.host}"
export env_harborUser="${appDeploySetting.harborServer.userName}"
export env_harborPassword="${appDeploySetting.harborServer.password}"
export env_nexusServerUrl="${appDeploySetting.nexusServer.nexusHttpUrl}"
export env_removeNpmLock="${appDeploySetting.removeNpmLock}"
export env_dockerBuildAddHostsParameters="${appDeploySetting.dockerBuildAddHostsParameters}"
export env_dockerBuildImage="${buildImageName}"
export env_dockerImage="${
        appDeploySetting.getRunImageFullName(log.language, log.languageVersion)
    }"
export env_jenkinsHomePathMountToDocker="${appDeploySetting.jenkinsServer.jenkinsHomePathMountToDocker}"
export env_bashImageName="${appDeploySetting.getOpsBaseBashImage()}"
export env_packageTool="${appDeploySetting.packageTool.value}"

function getPwdInDockerPath(){
    path=$1
    if [ "${'$'}path" == "" ]; then
        path=`pwd`
    fi
    
    if [ "${'$'}env_jenkinsHomePathMountToDocker" == "" ]; then
        echo ${'$'}path
        return ;
    fi
    
    #实际 =  挂载的外部目录 +  当前目录去除 /var/jenkins_home 部分
    echo ${'$'}env_jenkinsHomePathMountToDocker${'$'}{path:17}
}

export -f getPwdInDockerPath

         """
//    export env_resourceFileUrl=${appDeploySetting.resourceFileUrl}
    return FileContent("main-var.sh", content);
}


/**
 * 获取Jenkins部署的脚本文本
 */
fun JenkinsPublishJob.getK8sFiles(): List<FileContent> {
    var list = mutableListOf<FileContent>()

    list.add(getMainVarFile(this.task));
    list.addAll(FileContent.fromResources("devops/shell"));

    list.addAll(resFiles())

    list.addAll(this.buildFiles())



    list.forEach {
        if (!it.fileName.contains(".")) {
            return@forEach
        }


        var txt = it.bytes.toUtf8String()
            .replace("\r\n", "\n")
            .replace("\r", "\n")
            .replace("""＄""", "$");

        if (appDeploySetting.dockerEnvTimezone.HasValue) {
            txt = txt.replace(Regex("^ENV TZ=.*$"), "ENV TZ=\"${appDeploySetting.dockerEnvTimezone}\"")
        }

        it.bytes = txt.toByteArray()

    }
    return list;
}


private fun JenkinsPublishJob.replaceResVar(content: String): String {
    var nexusServer = this.appDeploySetting.nexusServer;

//    var mirror = this.appDeploySetting.mavenMirror
//    if (mirror.isNullOrEmpty()) {
//        if (nexusServer.hostUrl.isEmpty()) {
//            mirror = "http://maven.aliyun.com/nexus/content/groups/public/"
//        } else {
//            mirror = nexusServer.nexusHttpUrl + "/repository/maven-public/"
//        }
//    }

    return content
        .replace("""@vpath@""", "/" + this.task.buildInfo.location.replace("/", ""))
//        .replace("@mavenMirror@", mirror)
        .replace("@nexusHttpUrl@", nexusServer.nexusHttpUrl)
        .replace("@nexusWithoutHttpUrl@", nexusServer.nexusWithoutHttpUrl)
        .replace("@nexusUser@", nexusServer.userName)
        .replace("@nexusPassword@", nexusServer.password)
        .replace(
            "@base64Auth@",
            Base64Util.encode2Base64(nexusServer.userName + ":" + nexusServer.password)
        )
        .replace("@email@", nexusServer.email)
        .replace("""＄""", "$")
}

private fun JenkinsPublishJob.resFiles(): Collection<FileContent> {
    var list = mutableListOf<FileContent>();

    FileContent.fromResources("/devops/res")
        .forEach {

            var sects = it.fileName.split("/").toMutableList();
            if (sects[0] == "@any@") {
                sects[0] = this.task.language.toString().lowercase()
            }

            if (!(sects[0] basicSame this.task.language)) {
                return@forEach
            }

            if (sects.size > 1 && sects[1].IsInItems("@lib@", "@app@")) {
                if (sects[1] == "@lib@") {
                    if (!this.task.buildInfo.isLib) {
                        return@forEach
                    }
                    sects[1] = ""
                } else if (sects[1] == "@app@") {
                    if (!this.task.buildInfo.isApp) {
                        return@forEach
                    }
                    sects[1] = ""
                }
            }

            if (sects.size > 2 && sects[2] == "@folder@") {
                sects[2] = this.task.buildInfo.buildFolder
            }

            sects.removeAll { it == "." }
            sects.removeAll { it.isNullOrEmpty() }


            sects[0] = "res"
            it.fileName = sects.joinToString("/")

            var content = it.bytes.toUtf8String()
            it.bytes = this.replaceResVar(content).toByteArray()

            list.add(it)
        }

    // lib 不能用钩子。
    if (!(this.task.gitData?.isLib ?: false)) {
        var lang = appDeploySetting.languageSettings.firstOrNull { it.language == this.task.language };

        if (lang != null) {
            list.add(FileContent("res/sys-pre-build.sh", "source main-var.sh \nset -eo pipefail \n" + lang.preBuild))
            list.add(FileContent("res/sys-post-build.sh", "source main-var.sh \nset -eo pipefail \n" + lang.postBuild))
            list.add(FileContent("sys-pre-deploy.sh", "source main-var.sh \nset -eo pipefail \n" + lang.preDeploy))
            list.add(FileContent("sys-post-deploy.sh", "source main-var.sh \nset -eo pipefail \n" + lang.postDeploy))
        }
    }

    return list;
}
